/*
 * cartography.h
 *
 *  Created on: 08.04.2012
 *      Author: ignacio
 */



#include <ClanLib/Display/ImageProviders/png_provider.h>

//#include <boost/circular_buffer.hpp>
#include <vector>
using std::vector;
#include <list>
using std::list;
#include <iostream>
using std::ostream;
#include "vector.h"
#include "Astar.h"

namespace neurignacio
{

void cartography_example(void);

class BinaryMask
{
public:
	typedef unsigned char data_t;
	typedef CL_PixelBuffer buffer_t;
	typedef unsigned int size_t;
	typedef list<Vector3> VectorList;
protected:
	data_t** array;
	size_t width;
	size_t height;
public:
	BinaryMask(buffer_t& buffer);	// Cannot be (const buffer_t& buffer)
	BinaryMask(const size_t& width, const size_t& height, const data_t& backgroundValue=0);	// Cannot be (const buffer_t& buffer)
	BinaryMask(const BinaryMask& img);
	BinaryMask& operator=(const BinaryMask& img);
	~BinaryMask();
	data_t& operator() (const size_t &x, const size_t &y) {return array[y][x];}
	data_t operator() (const size_t &x, const size_t &y) const {return array[y][x];}
	data_t get_pixel(const size_t& x, const size_t& y) const;
	void set_pixel(const size_t& x, const size_t& y, data_t& value);
	size_t getWidth() {return width;}
	size_t getHeight() {return height;}

	void binarize(const data_t& threshold=1, const data_t& foreground=255, const data_t& background=0);
	void skeletonize(const data_t& foreground=1);	// foreground is the value of the pixels to skeletonize
	void skeletonize_ij(const data_t& foreground=1);	// foreground is the value of the pixels to skeletonize
	VectorList intersections(const BinaryMask::data_t& foreground=1);
	Hypergraph<Vector3> connections(VectorList& intersections, const BinaryMask::data_t& foreground=1);
//	void thin(const data_t& foreground=1);
	buffer_t getBuffer(void);
};

class CircularArray : public vector<BinaryMask::data_t>
{
public:
	typedef BinaryMask::size_t size_t;
	typedef BinaryMask::data_t data_t;
	typedef vector<BinaryMask::data_t> container_t;
public:
	size_t getIndex(const int& i) const;
public:
	CircularArray(void) : container_t() {}
	CircularArray(const size_t& size) : container_t(size) {}
	data_t& index(const int& i);
	data_t index(const int& i) const;
	data_t& operator[](const int& i) {return index(i);}
	data_t operator[](const int& i) const {return index(i);}

};

class StructuringElement
{
public:
	typedef BinaryMask::size_t size_t;
	typedef BinaryMask::data_t data_t;
	typedef CircularArray circular_array_t;
	typedef circular_array_t::iterator iterator;
	typedef circular_array_t::const_iterator const_iterator;
	typedef std::iterator<std::forward_iterator_tag, data_t> data_iterator;
public:
	circular_array_t ring;	// clock-wise starting at 12 o'clock
	data_t center;

public:
	StructuringElement(const size_t& size=9);
	data_t getCenter() const {return center;}
	data_t* getCenter() {return &center;}
	data_t& operator[](const int& i) {return ring[i];}
	data_t operator[](const int& i) const {return ring[i];}
	data_t& operator()(void) {return center;}
	data_t operator()(void) const {return center;}
	iterator begin(void) {return ring.begin();}
	const_iterator begin(void) const {return ring.begin();}
	iterator end(void) {return ring.end();}
	const_iterator end(void) const {return ring.end();}
	size_t size() const {return ring.size()+1;}
	size_t ringSize() const {return ring.size();}
	friend ostream& operator<<(ostream& out, const StructuringElement& element);
};

class PixelWindow : public StructuringElement
{
protected:
	BinaryMask* image;
	size_t x;
	size_t y;
public:
	PixelWindow(BinaryMask* img, const size_t& x=1, const size_t& y=1);
	void setCenter(const size_t& x, const size_t& y);
	void setCenter(const Vector3& v) {setCenter(v.x, v.y);}
	Vector3 pixel(const int& i);
	Vector3 centerPixel() const {return Vector3(x,y);}
	int findPixel(const size_t& x, const size_t& y);
	int findPixel(const Vector3& v) {return findPixel(v.x, v.y);}
};

} // end namespace neurignacio
